#include "headers.h"

void SyntacticAnalysis::SetRules(const QList<Rule> * rules)
{
    this->rules=rules;
}

const Rule* SyntacticAnalysis::GetRule(int index)
{
    if(rules==NULL)
        return NULL;
    return &rules->at(index);
}

bool SyntacticAnalysis::Reduse(const Rule* rule, QList<int>* StatesStack)
{
    if(rule==NULL)
        return false;
    AppendNodeToTree(rule->LHS, rule->RHS.size());
    for(int i=0; i<rule->RHS.size(); ++i)
        StatesStack->takeLast();
    Cell* cell=new Cell();
    gotoTable->GetValue(StatesStack->last(), rule->LHS, cell);
    if(cell->action==ERROR)
        return false;
    StatesStack->append(cell->value);
    return true;
}

void SyntacticAnalysis::ClearTree()
{
    if(this->tree!=NULL)
        tree->clear();
}

void SyntacticAnalysis::AppendNodeToTree(QString text, int children=0)
{
    if(tree==NULL)
        return;
    QTreeWidgetItem* topLevel=tree->topLevelItem(0);
    QTreeWidgetItem* newItem=new QTreeWidgetItem(QStringList()<<text);
    for(int i=0; i<children; ++i)
        newItem->insertChild(0, topLevel->takeChild(topLevel->childCount()-1));
    topLevel->addChild(newItem);
}

void SyntacticAnalysis::SetTopLevelItem(QString name)
{
    if(tree==NULL)
        return;
    tree->addTopLevelItem(new QTreeWidgetItem(QStringList()<<name));
}

void SyntacticAnalysis::ExpandTree()
{
    if(this->tree!=NULL)
        tree->expandAll();
}

void SyntacticAnalysis::ClearError()
{
    if(this->error!=NULL)
        this->error->Clear();
}

void SyntacticAnalysis::SetError(Error error)
{
    if(this->error!=NULL)
        *(this->error)=error;
}

bool SyntacticAnalysis::Analyze(QList<Lexeme>* lexemes, QTreeWidget* tree, Error* error)
{
    if(lexemes==NULL)
    {
        SetError(Error(0xff0, "Null pointer error"));
        return false;
    }
    this->tree=tree;
    this->error=error;
    ClearTree();
    SetTopLevelItem("Derivation");
    ClearError();

    QList<int> StatesStack;
    StatesStack.append(0);

    QListIterator<Lexeme> lexIter(*lexemes);

    if(!lexIter.hasNext())
        return true;
    Lexeme lex=lexIter.next();
    do
    {
        if(lex.type=="comment")
        {
            if(lexIter.hasNext())
                lex=lexIter.next();
            else
                lex=Lexeme("", "", QPoint(0,0));
            continue;
        }
        Cell* cell=new Cell();
        if(actionTable->GetValue(StatesStack.last(), lex.type, cell))
        {
            SetError(Error(0xfef, QObject::tr("Wrong state=\'%1\' or symbol=\'%2\' when adressing action table").arg(StatesStack.last()).arg(lex.type), (QObject*)new QPoint(lex.position.x(), lex.position.y())));
            return false;
        }
        switch(cell->action)
        {
        case SHIFT:
            AppendNodeToTree(lex.value);
            StatesStack.append(cell->value);
            if(lexIter.hasNext())
                lex=lexIter.next();
            else
                lex=Lexeme("", "", QPoint(0,0));
            break;
        case REDUSE:
            if(!Reduse(GetRule(cell->value), &StatesStack))
            {
                SetError(Error(0xfff3, QObject::tr("Unexpected symbol \'%1\' in state \'%2\'").arg(lex.value).arg(StatesStack.last()), (QObject*)&lex.position));
                return false;
            }
            break;
        case ACCEPT:
            ExpandTree();
            return true;
        case ERROR:
            SetError(Error(0xfff3, QObject::tr("Unexpected symbol \'%1\' in state \'%2\'").arg(lex.value).arg(StatesStack.last()), (QObject*)&lex.position));
            return false;
        default:
            SetError(Error(0xff2, "Wrong cell value in action table"));
            return false;
        }
    }while(true);
}

